package com.wynn.configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wynn.dao.PlanDao;
import com.wynn.dao.ProcedureDao;
import com.wynn.dao.ProductDao;
import com.wynn.dao.ProductLineDao;
import com.wynn.pojo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Component("planTask")
@Transactional
public class PlanTask {

    @Autowired
    private PlanDao planDao;
    @Autowired
    private ProcedureDao procedureDao;
    @Autowired
    private ProductLineDao productLineDao;
    @Value("${planCalculate.addr}")
    private String addr;

    @Async("taskExecutor")
    @Scheduled(cron = "${executorConfig.task-query}")
    public void timing(){
        Date date = new Date();

        List<ProductLine> allProductLine = productLineDao.findAllProductLine();
        //每日定时计算当日所有产线的排产
        for (ProductLine productLine : allProductLine) {
            PlanSummary planSummary = planDao.searchOnePlan(productLine, date);
            if (planSummary!=null){
                log.info("定时计算生产");
                planDao.addCalcuStatue(productLine.getId(),date,1);
                this.plan(planSummary);

            }
            log.info("当日无生产任务");
        }


    }

    @Async("taskExecutor")
    public void plan(PlanSummary planSummary)  {

        try {
            //用于存放Python结果
            String result = "";
            //产品名称
            List<String> lab = new ArrayList<>();
            //产品数量
            List<Integer> num = new ArrayList<Integer>();

            //节拍
            float tt = procedureDao.findTT();
            //工时表
            List<List<Float>> manhours = new ArrayList<>();
            Map<String, Integer> productsNum = planSummary.getProductsNum();
            for(Map.Entry<String,Integer> entry:productsNum.entrySet()){
                lab.add("'"+entry.getKey()+"'");//字符串必须加引号否则python识别不出来
                List<Float> hours = procedureDao.findHourByModel(entry.getKey());
                num.add(entry.getValue());
                manhours.add(hours);
            }


            //用于计算每个生产周期中，各产品生产数量得比例
            calPercent(num);

            String[] arguments = new String[]{"python",addr,num.toString(),lab.toString(),Float.toString(tt),manhours.toString()};
            //读取到python文件 并运行
            Process pr = Runtime.getRuntime().exec(arguments );
            InputStreamReader ir = new InputStreamReader(pr.getInputStream());
            LineNumberReader in = new LineNumberReader(ir);

            //获取到python中的所有print 数据，
            result += in.readLine();
            int length = result.length();
            //去掉字符转的[],并且按照", "划分成数组
            String[] split = result.substring(1,length-1).split(", ");

            //将计算出来的排产顺序封装到Schedule
            Class<?> scheduleClass= Schedule.class;
            Object tSchedule=scheduleClass.newInstance();
            //为producti赋值
            for (int i = 1; i < 33 ; i++) {
                Field filed = scheduleClass.getDeclaredField("product" + i);
                //去除字符串得引号
                String model = split[i-1].substring(1,split[i-1].length()-1);
                filed.setAccessible(true);
                filed.set(tSchedule,model);

            }
            //将object转化为具体对象
            ObjectMapper mapper = new ObjectMapper();
            Schedule schedule = mapper.convertValue(tSchedule,Schedule.class);
            //设置生产任务的时间和产线
            schedule.setProduceDate(planSummary.getProduceDate());
            schedule.setProductLine(planSummary.getProductLine());
            //保存排产计划
            planDao.addSchedule(schedule);

            log.info("计算时间"+ new Date());
            log.info("产品名称"+ lab.toString());
            log.info("产品数量"+num.toString());
        }catch (IOException e) {
            log.warn("计算生产日失败");
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }finally {
            planDao.deleteCalcuStatue(planSummary.getProductLine().getId(),planSummary.getProduceDate());
        }

    }


    //用于计算每个生产周期中，各产品生产数量得比例
    private void calPercent(List<Integer> num){
        int sum = 0;
        for (Integer integer : num) {
            sum+=integer;
        }
        //计算比例
        double percent = sum/32.0;
        //根据比例调整
        int sum2=0;
        for (int i = 0; i < num.size(); i++) {
            num.set(i, (int) (num.get(i)/percent));
            sum2+=num.get(i);
        }
        //补差额
        for (int i = 0; i <32-sum2 ; i++) {
            num.set(i,num.get(i)+1);
        }

    }

}
